package com.ai.zuochengyun.phase01.class01;

import java.util.*;

public class Code16_EveryStepShowBoss {

    public static List<List<Integer>> topK(int[] arr, boolean[] op, int k) {
        return operate(arr, op, k);
    }

    public static List<List<Integer>> operate(int[] arr, boolean[] op, int k) {
        Map<Integer, Code16_Customer> map = new HashMap<>();
        // 候选区
        List<Code16_Customer> candidate = new ArrayList<>();
        List<Code16_Customer> winner = new ArrayList<>();
        List<List<Integer>> ans = new ArrayList<>();
        for (int i = 0; i < arr.length; i++) {
            int no = arr[i];
            boolean buyOrRefund = op[i];
            // 如果没有购买，但是发生了退货，则视为无效事件
            if (!buyOrRefund && !map.containsKey(no)) {
                ans.add(getCurAns(winner));
                continue;
            }

            // 进入这里，表明可能发生如下3中情况
            // 1、用户之前购买数为0，此时买货
            // 2、用户之前购买数大于0，此时买货
            // 3、用户之前购买数大于0，此时退货

            // 顾客之前不存在，先初始化一个顾客
            if (!map.containsKey(no)) {
                map.put(no, new Code16_Customer(no, 0, 0L));
            }

            // 获取当前顾客
            Code16_Customer Code16_Customer = map.get(no);
            if (buyOrRefund) {
                Code16_Customer.buy++;
            } else {
                Code16_Customer.buy--;
            }

            // 如果购买数为0，从列表中移除
            if (Code16_Customer.buy <= 0) {
                map.remove(no);
            }

            // 候选区和得奖区都没有，表明你刚开始购买了一件商品
            if (!candidate.contains(Code16_Customer) && !winner.contains(Code16_Customer)) {
                Code16_Customer.enterTime = System.currentTimeMillis();
                if (winner.size() < k) {
                    // 记录进入得奖区的进入时间，并将当前顾客放入得奖区
                    winner.add(Code16_Customer);
                } else {
                    // 如果得奖区已满，就加入候选区
                    candidate.add(Code16_Customer);
                }
            }

            // 清除得奖区和购买区数量为0的客户
            clearZeroBuy(candidate);
            clearZeroBuy(winner);

            // 从大到小排序
            candidate.sort(new Code16_Customer.CandidateComparator());
            winner.sort(new Code16_Customer.WinnerComparator());

            // 调整两个区域的元素
            move(candidate, winner, k);
            ans.add(getCurAns(winner));
        }
        return ans;
    }

    private static void clearZeroBuy(List<Code16_Customer> area) {
        area.removeIf(Code16_Customer -> Code16_Customer.buy <= 0);
    }

    /**
     * 调整候选区和得奖区的元素
     *
     * @param cands
     * @param daddy
     * @param k
     */
    private static void move(List<Code16_Customer> cands, List<Code16_Customer> daddy, int k) {
        // 候选区为空
        if (cands.isEmpty()) {
            return;
        }

        // 候选区不空
        if (daddy.size() < k) {
            // 得奖区不满
            // 将候选区从大到小排序的第一个元素加入到得奖区
            Code16_Customer Code16_Customer = cands.get(0);
            Code16_Customer.enterTime = System.currentTimeMillis();
            daddy.add(Code16_Customer);
            cands.remove(0);
        } else {
            // 得奖区已满，替换
            int last = daddy.size() - 1;
            if (cands.get(0).buy > daddy.get(last).buy) {
                // 将之前中奖区的选手从中奖区转移到候选区
                // 将之前候选区的选手从候选区转移到中奖区
                Code16_Customer degrade = daddy.get(last);
                daddy.remove(last);
                degrade.enterTime = System.currentTimeMillis();

                Code16_Customer upgrade = cands.get(0);
                cands.remove(0);
                upgrade.enterTime = degrade.enterTime;

                daddy.add(upgrade);
                cands.add(degrade);
            }
        }
    }

    private static List<Integer> getCurAns(List<Code16_Customer> daddy) {
        List<Integer> ans = new ArrayList<>();
        for (Code16_Customer customer : daddy) {
            ans.add(customer.id);
        }
        return ans;
    }

    /**
     * 候选区排序规则
     */
    public static class CandidateComparator implements Comparator<Code16_Customer> {

        @Override
        public int compare(Code16_Customer o1, Code16_Customer o2) {
            // 购买越大的放前面，如果购买数相同，谁早谁在前。
            return o1.buy != o2.buy ? o2.buy - o1.buy : (int) (o1.enterTime - o2.enterTime);
        }
    }

    /**
     * 得奖区排序规则，因为要替换前面的元素
     */
    public static class DaddyComparator implements Comparator<Code16_Customer> {

        @Override
        public int compare(Code16_Customer o1, Code16_Customer o2) {
            // 购买越大的放前面，如果购买数相同，
            // 谁后买谁在前，因为前者先买但是目前并未发生新的购买，可能购买力没有后来的强，那么后面在替换的时候，优先替换掉最早购买的
            return o1.buy != o2.buy ? o2.buy - o1.buy : (int) (o2.enterTime - o1.enterTime);
        }
    }
}
